unit uBlob;

interface

uses
  Windows, Sysutils, Graphics, MMSystem, Classes;
type
  TData = packed record
            used: Boolean;
            left,
            right,
            top,
            bottom: SmallInt;
            Count: SmallInt;
            fine: Boolean;
          end;

  TFinger = packed record
              used: Boolean;
              firstTime: LongInt;
              lastFoundTime: LongInt;
              Coords: TPoint;
              Dir: TPoint;
            end;
  TBlob = class
  private
    _th: Byte;
    _th2: Byte;
    _th3: Word ;
    _draw: Boolean;
    _cleanCanvas: Boolean ;
  public
    constructor create;

    procedure Blob_Tracking ( var Data_Points: array of TData;
                            var Finger: array of TFinger;
                            _outCanvas: TCanvas );

    procedure Blob_Detection ( src: TBitmap;
                             var Data_Points: array of TData;
                             th: Byte = 255);
  end;




implementation


constructor TBlob.create;
begin
      _th:= 10;
      _th2:= 10;
      _th3:= 10;
      _draw:= true;
      _cleanCanvas:= false;

end;
procedure TBlob.Blob_Tracking ( var Data_Points: array of TData;
                          var Finger: array of TFinger;
                          _outCanvas: TCanvas);
var
  x, y, Counter, Counter2: SmallInt;
  _time: LongInt;
  found: Boolean;
  data: Integer;
begin
  data:= length(Data_points) ;
//  SetLength(Finger,data );
  if _draw and _cleanCanvas then begin
    _outCanvas.Brush.Color := clWhite;
    _outCanvas.Rectangle ( _outcanvas.ClipRect );
  end;

  _time := TimeGetTime;


  for Counter := 1 to High ( Data_Points ) do
    if Data_Points [ Counter ].used then begin
      with Data_Points [ Counter ] do begin

        // Blob-Size-Test
        if ( Right - left > _th2 ) and ( bottom - top > _th2 ) then begin

          x := ( Left + Right ) div 2;
          y := ( top + bottom ) div 2;
          if _draw then begin
            // zeichnen der blobs
            _outCanvas.Pen.Color := clRed;
            _outCanvas.Brush.Style := bsClear;
            _outCanvas.Rectangle ( left, Top, Right, bottom );
            _outCanvas.Pen.Color := clBlue;
            _outCanvas.Ellipse ( x + 5 , y +5 , x +5 , y +5  );
            _outCanvas.Brush.Style := bsSolid;
          end;


          for Counter2 := 1 to High ( Finger ) do
            if Finger [ Counter2 ].used then
              if _time - Finger [ Counter2 ].lastFoundTime > _th3 then
                Finger [ Counter2 ].used := false;

          found := false;

          for Counter2 := 1 to High ( Finger ) do
            if Finger [ Counter2 ].used then begin
              with Finger [ Counter2 ] do
                if ( Abs ( x - Coords.X ) < _th )
                 and ( Abs ( y - Coords.Y ) < _th ) then begin
                  lastFoundTime := _time;
                  // set new Coords
                  Coords := Point ( ( x + Coords.X ) div 2,
                                    ( y + Coords.Y ) div 2 );
                  // compute the Direction
                  Dir := Point ( Coords.X - x,
                                 Coords.Y - y );

                  found := true;
                  break;
                end;
            end;


          if not found then
            for Counter2 := 1 to High ( Finger ) do
              if not Finger [ Counter2 ].used then begin
                Finger [ Counter2 ].used := true;
                Finger [ Counter2 ].firstTime := _time;
                Finger [ Counter2 ].lastFoundTime := _time;
                Finger [ Counter2 ].Coords := Point ( x, y );
                Finger [ Counter2 ].Dir := Point ( 0, 0 );

                break;
              end;

           // draw finger
           if _draw then
             for Counter2 := 1 to High ( Finger ) do
               if Finger [ Counter2 ].used then begin
                 _outCanvas.Pen.Color := clBlue;
                 _outCanvas.Ellipse ( Finger [ Counter2 ].Coords.X - 3,
                                      Finger [ Counter2 ].Coords.Y - 3,
                                      Finger [ Counter2 ].Coords.X + 3,
                                      Finger [ Counter2 ].Coords.Y + 3 );

                 _outCanvas.TextOut ( Finger [ counter2 ].Coords.X + 10,
                                      Finger [ Counter2 ].Coords.Y,
                                      Format('Titik: %d',[Counter2]));
               end;

        end else begin
          Data_Points [ Counter ].fine := false;
        end;
      end;

      Data_Points [ Counter ].used := false;
      Data_Points [ Counter ].fine := false;
    end;
end;
procedure TBlob.Blob_Detection ( src: TBitmap;
                           var Data_Points: array of TData;
                           th: Byte = 255);
var
  ps, ps2, ps3: PByteArray;
  x, y: SmallInt;
  Data, temp, found: Boolean;
  Counter, Data_Count, Data_last: SmallInt;
begin
  Data_Count := 0;
  temp := false;
  Data_last := 0;

  ps2 := src.ScanLine [ 0 ];
  ps3 := src.ScanLine [ 1 ];
  for y := 2 to src.Height - 3 do begin
    ps := ps2;
    ps2 := ps3;
    ps3 := src.ScanLine [ y + 1 ];
    for x := 0 to src.Width - 2 - 4 do begin

      Data := false;

      if ps [ x  ]  = th then begin
          if ( ps [  x + 1  ] =  th )
           and ( ps [ x + 2  ]  =  th )
           and ( ps [ x + 3   ]  =  th )
          // and ( ps [ x + 4  ] <> th )
           and ( ps2 [x] = th )
           and ( ps2 [ x + 1] = th )
           and ( ps2 [ x + 2 ] = th )
           and ( ps2 [ x + 3   ] = th )
          // and ( ps2 [ ( x + 4 )  ] = th )
           and ( ps3 [ x ] = th )
           and ( ps3 [ x + 1 ] = th )
           and ( ps3 [ x + 2  ] = th )
           and ( ps3 [ x + 3  ] = th )

           then begin

            ps [ x ] := 0;
            ps [ x + 1] := 0;
            ps [ x + 2] := 0;
           ps [ x - 1] := 0;
            ps [ ( x - 1 ) + 1 ] := 0;
            ps [ ( x - 1 ) + 2 ] := 0;
            ps [ x - 2 ] := 0;
            ps [ ( x - 2 ) + 1 ] := 0;
            ps [ ( x - 2 ) + 2 ] := 0;
            ps2 [  x - 1 ] := 0;
            ps2 [ ( x - 1 ) + 1 ] := 0;
            ps2 [ ( x - 1 )  + 2 ] := 0;
            ps2 [  x - 2   ] := 0;
            ps2 [ ( x - 2 )  + 1 ] := 0;
            ps2 [ ( x - 2 )  + 2 ] := 0;
            ps3 [  x - 1   ] := 0;
            ps3 [ ( x - 1 ) + 1 ] := 0;
            ps3 [ ( x - 1 ) + 2 ] := 0;
            ps3 [  x - 2   ] := 0;
            ps3 [ ( x - 2 ) + 1 ] := 0;
            ps3 [ ( x - 2 ) + 2 ] := 0;
           
            // found point
          Data := true;
          end else begin

            ps [ x ] := 255;
            ps [ x  + 1 ] := 255;
            ps [ x  + 2 ] := 255;


          end;
      end;
      if Data then
        if temp then begin
         end else begin
             temp := true;

          if Data_Count = 0 then begin
       //     SetLength(Data_Points, Data_Count);
            Inc ( Data_Count );

            if Data_Count > High ( Data_Points ) then
              Data_count := High ( Data_Points );

            Data_Points [ Data_Count ].used := true;
            Data_Points [ Data_Count ].left := x;
            Data_Points [ Data_Count ].top := y;
            Data_Points [ Data_Count ].right := x;
            Data_Points [ Data_Count ].bottom := y;
            Data_Points [ Data_Count ].count := 0;
            Data_Points [ Data_Count ].fine := true;

            Data_last := Data_Count;
          end else
            found := false;

          for Counter := 1 to Data_Count do
            if ( ( Abs ( Data_Points [ Counter ].left - x ) < 10 )
             and ( Abs ( Data_Points [ Counter ].Count + Data_Points [ Counter ].Top - y ) < 2 ) ) then begin

            if x < Data_Points [ Counter ].left then Data_Points [ Counter ].left := x;
              Inc ( Data_Points [ Counter ].Count );

            Data_last := Counter;
            found := true;
            break;
          end;

          if not found then begin
            Inc ( Data_Count );
            Data_Points [ Data_Count ].used := true;
            Data_Points [ Data_Count ].left := x;
            Data_Points [ Data_Count ].top := y;
            Data_Points [ Data_Count ].right := x;
            Data_Points [ Data_Count ].bottom := y;
            Data_Points [ Data_Count ].count := 0;
            Data_Points [ Data_count ].fine := true;

            Data_last := Data_count;
          end;

        end
      else
        if temp then begin
          temp := false;

          if x > Data_Points [ Data_last ].Right then
            Data_Points [ Data_last ].Right := x;

          Data_Points [ Data_last ].bottom := y;
        end else begin
        end;

    end;
  end;

end; // <- Blob_Detection
end.
